package org.xbrlapi.data.bdbxml.examples.tests;


import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;

import org.apache.log4j.Logger;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.xbrlapi.Fact;
import org.xbrlapi.Instance;
import org.xbrlapi.aspects.AspectValue;
import org.xbrlapi.aspects.FactSet;
import org.xbrlapi.aspects.FactSetImpl;
import org.xbrlapi.cache.CacheImpl;
import org.xbrlapi.data.Store;
import org.xbrlapi.data.bdbxml.StoreImpl;
import org.xbrlapi.loader.Loader;
import org.xbrlapi.networks.AnalyserImpl;
import org.xbrlapi.networks.Storer;
import org.xbrlapi.networks.StorerImpl;
import org.xbrlapi.sax.EntityResolver;
import org.xbrlapi.sax.EntityResolverImpl;
import org.xbrlapi.utilities.XBRLException;
import org.xbrlapi.xdt.LoaderImpl;
import org.xbrlapi.xdt.aspects.DimensionalAspectModel;
import org.xbrlapi.xdt.aspects.DimensionalAspectModelWithStoreCachingLabellers;
import org.xbrlapi.xlink.XLinkProcessor;
import org.xbrlapi.xlink.XLinkProcessorImpl;
import org.xbrlapi.xlink.handler.XBRLCustomLinkRecogniserImpl;
import org.xbrlapi.xlink.handler.XBRLXLinkHandlerImpl;

/**
 * Tests fact loading into a fact set to see if the aspect model
 * that results is independent of the loading sequence for the facts.
 */
public class MattDeAngelis2TestCase extends BaseTestCase {

    // Create the logger
    protected static Logger logger = Logger.getLogger(LoadTestCase.class);

    @BeforeMethod
    protected void setUp() throws Exception {
        super.setUp();
    }

    @AfterMethod
    protected void tearDown() throws Exception {
        super.tearDown();
    }

    private Loader getLoader(Store store) throws XBRLException {
        XBRLXLinkHandlerImpl xlinkHandler = new XBRLXLinkHandlerImpl();
        XBRLCustomLinkRecogniserImpl clr = new XBRLCustomLinkRecogniserImpl();
        XLinkProcessor xlinkProcessor = new XLinkProcessorImpl(xlinkHandler, clr);

        File cacheFile = new File(cache);

        // Rivet errors in the SEC XBRL data require these remappings - may not be needed anymore...
        HashMap<URI, URI> map = new HashMap<URI, URI>();
        try {
            map.put(new URI("http://www.xbrl.org/2003/linkbase/xbrl-instance-2003-12-31.xsd"), new URI("http://www.xbrl.org/2003/xbrl-instance-2003-12-31.xsd"));
            map.put(new URI("http://www.xbrl.org/2003/instance/xbrl-instance-2003-12-31.xsd"), new URI("http://www.xbrl.org/2003/xbrl-instance-2003-12-31.xsd"));
            map.put(new URI("http://www.xbrl.org/2003/linkbase/xbrl-linkbase-2003-12-31.xsd"), new URI("http://www.xbrl.org/2003/xbrl-linkbase-2003-12-31.xsd"));
            map.put(new URI("http://www.xbrl.org/2003/instance/xbrl-linkbase-2003-12-31.xsd"), new URI("http://www.xbrl.org/2003/xbrl-linkbase-2003-12-31.xsd"));
            map.put(new URI("http://www.xbrl.org/2003/instance/xl-2003-12-31.xsd"), new URI("http://www.xbrl.org/2003/xl-2003-12-31.xsd"));
            map.put(new URI("http://www.xbrl.org/2003/linkbase/xl-2003-12-31.xsd"), new URI("http://www.xbrl.org/2003/xl-2003-12-31.xsd"));
            map.put(new URI("http://www.xbrl.org/2003/instance/xlink-2003-12-31.xsd"), new URI("http://www.xbrl.org/2003/xlink-2003-12-31.xsd"));
            map.put(new URI("http://www.xbrl.org/2003/linkbase/xlink-2003-12-31.xsd"), new URI("http://www.xbrl.org/2003/xlink-2003-12-31.xsd"));
        } catch (URISyntaxException e) {
            e.printStackTrace();
            Assert.fail("A URI has invalid syntax.");
        }
        EntityResolver entityResolver = new EntityResolverImpl(cacheFile, map);
        Loader myLoader = new LoaderImpl(store, xlinkProcessor, entityResolver);
        myLoader.setCache(new CacheImpl(cacheFile));
        myLoader.setEntityResolver(entityResolver);
        xlinkHandler.setLoader(myLoader);
        return myLoader;
    }

    @Test
    public void testFactSetPopulation() {
        StoreImpl store = null;
        try {
            store = createStore("mattDeAngelis");
            store.setAnalyser(new AnalyserImpl(store));
            URI targetURI = URI.create("http://www.sec.gov/Archives/edgar/data/1090872/000104746911010124/a-20111031.xml");
            Loader loader = getLoader(store);
            loader.discover(targetURI);

            Storer storer = new StorerImpl(store);
            Loader xdtLoader = getLoader(store);
            xdtLoader.discover(targetURI);
            if (!store.hasAllRelationships(targetURI)) {
                storer.storeAllRelationships();
            }
            store.setAnalyser(new AnalyserImpl(store));

            System.out.println("Getting instance...");
            List<Instance> instances = store.getFragmentsFromDocument(targetURI, "Instance");
            if (instances.size() > 1)
                throw new XBRLException("There are duplicates of the target instance in the data store.  The store appears to be corrupted.");
            if (instances.size() == 0)
                throw new XBRLException("The target document, " + targetURI + ",is not an XBRL instance.");
            Instance instance = instances.get(0);
            DimensionalAspectModel aspectModel = new DimensionalAspectModelWithStoreCachingLabellers(store);
            aspectModel.initialise();
            FactSet sgafactSet = new FactSetImpl(aspectModel);
            List<Fact> sgafacts = instance.getFacts("http://fasb.org/us-gaap/2011-01-31", "SellingGeneralAndAdministrativeExpense");
            sgafactSet.addFacts(sgafacts);
            System.out.println("Printing SG&A Facts from set containing only SGA&A facts...");
            for (Fact fact : sgafactSet.getFacts()) {
                for (AspectValue av : sgafactSet.getAspectValues(fact)) {
                    System.out.println("Concept: " + fact.getConcept().getName() + " and AspectValue: " + av.getId());
                }
            }

            FactSet revfactSet = new FactSetImpl(aspectModel);
            List<Fact> revfacts = instance.getFacts("http://fasb.org/us-gaap/2011-01-31", "SalesRevenueNet");
            revfactSet.addFacts(revfacts);
            revfactSet.addFacts(sgafacts);
            System.out.println("Printing SG&A Facts from set containing SGA&A and Revenue facts...");
            for (Fact fact : sgafactSet.getFacts()) {
                for (AspectValue av : revfactSet.getAspectValues(fact)) {
                    System.out.println("Concept: " + fact.getConcept().getName() + " and AspectValue: " + av.getId());
                }
            }

            List<Fact> benefitfacts = instance.getFacts("http://fasb.org/us-gaap/2011-01-31", "DefinedBenefitPlanAmortizationOfGainsLosses");
            FactSet revsgabenfactSet = new FactSetImpl(aspectModel);
            revsgabenfactSet.addFacts(benefitfacts);
            revsgabenfactSet.addFacts(revfacts);
            revsgabenfactSet.addFacts(sgafacts);
            System.out.println("Printing SG&A Facts from set containing SGA&A, Revenue and Defined Benefit Plan facts...");
            for (Fact fact : sgafactSet.getFacts()) {
                for (AspectValue av : revsgabenfactSet.getAspectValues(fact)) {
                    System.out.println("Concept: " + fact.getConcept().getName() + " and AspectValue: " + av.getId());
                }
            }

        } catch (Exception e) {
            Assert.fail("Unexpected: " + e.getMessage());
        } finally {
            try {
                //if (store!= null) store.delete();
            } catch (Exception x) {
                Assert.fail("The store could not be deleted.");
            }
        }
    }

}